import socket
import re
import subprocess
from optparse import OptionParser
import time

def portScanner(host, port, protocol):

	#UDP
	if protocol.upper() == 'UDP':
		""" CLIENT """
		dataToSend = "Hello from UDP client"
		client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		while 1:
			client.sendto(dataToSend, (host, port))
			print "Sent:", dataToSend
			time.sleep(1)

	#TCP
	if protocol.upper() == 'TCP':
		tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		tcp.connect((host, port))
		if not port == 80:
			tcp.send("hello")
		else:
			tcp.send("GET / HTTP/1.0\r\n\r\n")
		return tcp.recv(200)
		tcp.close()

def pingSweep(ip_from_user):
		ping = subprocess.Popen(
		    ["ping", ip_from_user],
		    stdout = subprocess.PIPE,
		    stderr = subprocess.PIPE
		)
		out, error = ping.communicate()
		m = re.search('(\d+\.\d+\.\d+\.\d+)', out)
		#ip = m.group(0)
		return out

def bannerGrabbing(host, port, protocol):

	header = portScanner(host, port, protocol)

	if header:
		try:
			#HTTP
			Server_linux = ['apache', 'nginx']
			Server_microsoft = ['iis','win']
			X_Powered_By = ['php','asp']
			if port == 80:
				service_name = re.search(re.compile(r'^Server\:(.*)$', re.I|re.M), header)
				source_code = re.search(re.compile(r'^X-Powered-By\:(.*)$', re.I|re.M), header)
				if service_name.group(0):
					print "I found: HTTP"
					#Operating System banner
					print "  Banner:" ,service_name.group(0)[8:] # 8 is the size of "Server: "
					for service in Server_linux:
						if service in service_name.group(0).lower():
							print " ",host,"is Linux"

					if 'iis' in service_name.group(0).lower():
						print " ",host,"is Windows"
					
					#Source code banner
					for source in X_Powered_By:
						if source_code.group(0):
							print "  Source:" ,source_code.group(0)[14:] #X-Powered-By header
							break
						
			#SSH
			if port == 22:
				service_name = re.search(re.compile('SSH', re.I|re.M), header)
				print "I found: " ,service_name.group(0)
			#FTP
			if port == 21:
				service_name = re.search(re.compile('FTP', re.I|re.M), header)
				print "I found: " ,service_name.group(0)
			if port == 3306:
				service_name = re.search(re.compile('MySQL', re.I|re.M), header)
				print "I found: " ,service_name.group(0)

		except Exception, e:
			return e
	else:
		print "[!] Error occured while grabbing the header."


if __name__ == '__main__':
	parser=OptionParser()
	parser.add_option("-t", dest="host", type="string",
					help="Enter target name or ip", metavar="www.exemple.com")
	parser.add_option("-i", dest="interval", type="int", default=0,
					help="Time interval between each scan in seconds", metavar="TIME_INTERVAL")
	parser.add_option("-p", dest="protocol", type="string",
					help="Returns the type of scan.", metavar="[TCP/UDP/ICMP]")
	#parser.add_option("-s", dest="protocols", type="string",
	#				help="[full/stealth/fin/ack]", metavar="SCAN TYPE")
	#parser.add_option("-P", dest="port_range", type="string",
	#				help="Ports range: 1-10000 or 1,2,3 etc", metavar="PORT RANGE")
	parser.add_option("-b", dest="banner", type="int",
					help="Set to 1 for Banner Grabbing")

	(options, args)=parser.parse_args()
	if options.host==None or options.protocol==None:
		parser.print_help()
	else:
		host=options.host
		protocol = options.protocol
		banner = options.banner
		interval = options.interval
		ports=[21,22,25,80,443,3306]
		try:  
			ip=socket.gethostbyname(host) # Domain name to IP
			if ip:
				print("[+] Running scan on %s"%host)
				print("[+] Target IP: %s"%ip)
				
				if protocol:
					if protocol == 'TCP':
						if options.banner:
							print "\n========== OS fingerprinting Started ========\n"
							# Looking for banners
							for port in ports:
								try:
									banner_payload = bannerGrabbing(host, port, protocol)
									if not banner_payload == None:
										print banner_payload
								except:
									print "[!] port", port, "has no fingerprint"
					
						print "\n========== Port Scanner Started =========\n"
						# Scanning for open ports
						counter =0
						for port in ports:
							try:
								payload = portScanner(host, port, protocol)	
								print "port %s is open!" % port
								counter +=1
								#print "Here is the header:\n%s" % payload
							except:
								print "port %s is closed on %s" % (port,protocol)
						print "\n[*]",len(ports), "ports were scanned.\n   ", counter ,"of them are open."
					
					if protocol == 'UDP':
						udp = portScanner('localhost', 5454, protocol)
						if not udp == None:
							print udp
						else:
							"Encountered a problem with UDP connection"
					
					if protocol == 'ICMP':
						#Scanning Class C for the host ip
						results = ['Request timed out', 'Destination net unreachable']
						print "\n========== Ping Sweep Started =========\n" 
						try:
							class_c = re.search(r'\d+\.\d+\.\d+\.', ip)
							for i in range(1,254):
								if interval>0:
									time.sleep(interval)
								ping_payload = pingSweep(class_c.group(0)+str(i))
								for message in results:
									if message in ping_payload:
										print class_c.group(0)+str(i) + " returned " + message
										break
									else:
										print class_c.group(0)+str(i) + " is UP!"
										break
						except KeyboardInterrupt:
							print "[!] User canceled the operation"
						except Exception:
							print "[!] Invalid host"
				else:
					print "[!] Please supply protocol [TCP/ICMP]"
		except KeyboardInterrupt:
			print "[!] User canceled the operation"
		except Exception, e:
			print "[!] Invalid options."
			print e